//
//  Lattice.h
//  phi_four
//
//  Created by Snir Gazit on 3/8/12.
//  Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//

#ifndef Lattice_h
#define Lattice_h

#include "../HelpLibs/ArrayMultiD.h"
#include "../HelpLibs/def.h"

using namespace std;
using namespace boost;

typedef boost::array<int, DIM> IndexType;

enum CreateRemove {
	CREATE = 0, REMOVE = 1
};

enum SectorType {
	ZSECTOR = 0, GXY = 1
};

typedef boost::array<int, 2> XYBondType;

struct Site {
	typedef ArrayMulti<Site, DIM> SiteArray;
	typedef SiteArray::iterator SiteArrayIterator;
	typedef SiteArray::IterIndex SiteArrayIndexIterator;
	typedef boost::array<XYBondType*, 2 * DIM> XYBondArray;
	typedef boost::array<SiteArrayIterator, 2 * DIM> NSiteArray;

	XYBondArray XYBondArray_;
	NSiteArray nSiteArray_;
	int XYTotalBonds_;
	int& getTotalBonds() {
		return XYTotalBonds_;
	}
	XYBondArray& getBondArray() {
		return XYBondArray_;
	}
	friend class serialization::access;
	template<class Archive>
	void serialize(Archive & ar, const unsigned int version) {
		ar & XYTotalBonds_;
	}
};

struct Lattice {
	// Typedefs
	// XY Bonds
	typedef boost::array<XYBondType, DIM> XYBondData;
	typedef XYBondData::iterator XYBondDataVectorIterator;
	// Site Iterator
	typedef Site::SiteArrayIterator SiteIter;
	typedef Site::SiteArrayIndexIterator SiteIterIndex;
	// Bond Array
	typedef ArrayMulti<XYBondData, DIM> XYBondArray;
	typedef XYBondArray::iterator XYBondArrayIter;
	typedef XYBondArray::IterIndex XYBondArrayIterIndex;
	// functions
	void init(IndexType const &latSize);
	void initSquare(IndexType const &latSize);
	SiteIter getIra();
	SiteIter getMasha();
	void setIra(Lattice::SiteIter &iter);
	void setMasha(Lattice::SiteIter &iter);
	SiteIter getSite(int distanceFromStart);
	boost::array<int, DIM> getSizes();
	bool isClosed() const;
	void moveIraMasha(IndexType moveToPos);
	int getCordinationNumber() const;
	int getNumOfSites() const;
	// Debug Functions
	bool testConfiguration(int &totalBonds);
	// Measure Functions
	XYBondArrayIter XYBondBegin();
	XYBondArrayIter XYBondEnd();
	XYBondArrayIterIndex XYBondBeginIndex();
	XYBondArrayIterIndex XYBondEndIndex();
	SiteIter siteBegin();
	SiteIter siteEnd();
	SiteIterIndex siteBeginIndex();
	SiteIterIndex siteEndIndex();
	IndexType iraIndex();
	IndexType mashaIndex();
	SectorType getSectorType() const;
	void setSectorType(SectorType sectorType);
	int getTotalBonds() const;
	void setToalBonds(int totalBonds);
	void dump(string fileName, bool final, ofstream *outFile);
	void read(string fileName);
	template<class Archive>
	void save(Archive & ar, const unsigned int version) const;
	template<class Archive>
	void load(Archive & ar, const unsigned int version);BOOST_SERIALIZATION_SPLIT_MEMBER()Site::SiteArray siteLattice_;
	XYBondArray XYBondLattice_;
	SiteIter ira_, masha_;
	boost::array<int, DIM> latSize_;
	int cordinationNumber_;
	SectorType sectorType_;
	int totalBonds_;
};
template<class Archive>
void Lattice::save(Archive & ar, const unsigned int version) const {
	for (auto itb = XYBondLattice_.begin(); itb != XYBondLattice_.end(); itb++)
		for (auto itd = itb->begin(); itd != itb->end(); itd++)
			ar & *itd;
	for (auto itb = siteLattice_.begin(); itb != siteLattice_.end(); itb++)
		ar & *itb;
	int ira = ira_ - siteLattice_.begin();
	ar & ira;
	int masha = masha_ - siteLattice_.begin();
	ar & masha;
	ar & totalBonds_;
	ar & sectorType_;
}
template<class Archive>
void Lattice::load(Archive & ar, const unsigned int version) {
	for (auto itb = XYBondLattice_.begin(); itb != XYBondLattice_.end(); itb++)
		for (auto itd = itb->begin(); itd != itb->end(); itd++)
			ar & *itd;
	for (auto itb = siteLattice_.begin(); itb != siteLattice_.end(); itb++)
		ar & *itb;
	int ira;
	ar & ira;
	ira_ = this->siteBegin() + ira;
	int masha;
	ar & masha;
	masha_ = this->siteBegin() + masha;
	ar & totalBonds_;
	ar & sectorType_;

}
#endif
